#!/bin/bash

set -euo pipefail
IFS=$'\n\t'

RELEASE_TYPE=${1:-}
PREID=${2:-}

echo_help() {
  cat << EOF
USAGE:
    ./scripts/publish <release_type> <pre_id>

ARGS:
    <release_type>
            A Semantic Versioning release type used to bump the version number. Either "patch", "minor", "major", "prepatch", "preminor", "premajor", or "prerelease".
    <pre_id>
            Adds an identifier to be used to prefix premajor, preminor, prepatch or prerelease version increments. Either "alpha" or "beta".
EOF
}

create_github_release() {
  if which hub | grep -q "not found"; then
    create_github_release_fallback
    return
  fi

  # Get the last two releases. For example, `("v1.3.1" "v1.3.2")`
  local versions=($(git tag --sort version:refname | grep '^v' | tail -n 2))

  # If we didn't find exactly two previous version versions, give up
  if [ ${#versions[@]} -ne 2 ]; then
    create_github_release_fallback
    return
  fi

  local previous_version="${versions[0]}"
  local current_version="${versions[1]}"
  local commit_titles=$(git log --pretty=format:"- %s" "$previous_version".."$current_version"^)
  local release_notes="$(cat << EOF
$current_version

<!-- Please group the following commits into one of the sections below. -->
<!-- Remove empty sections when done. -->

$commit_titles

### New features

### Fixes

### Changed

EOF
)"

  echo "Creating GitHub release"
  echo ""
  echo -n "    "
  hub release create -em "$release_notes" "$current_version"
}

create_github_release_fallback() {
  cat << EOF
Remember to create a release on GitHub with a changelog notes:

    https://github.com/stripe/stripe-js/releases/new

EOF
}

verify_commit_is_signed() {
  local commit_hash=$(git log -1 --format="%H")

  if ! git verify-commit "$commit_hash" &> /dev/null; then
    echo "Error! Commit $commit_hash is not signed"
    echo "Please follow https://docs.github.com/en/authentication/managing-commit-signature-verification/adding-a-gpg-key-to-your-github-account and sign your commit"
    exit 1
  fi
}

check_github_token() {
  if [[ -z "${GITHUB_TOKEN}" ]]; then
    echo "GITHUB_TOKEN is not set."
    exit 1
  fi
}

# Show help if no arguments passed
if [ $# -eq 0 ]; then
  echo "Error! Missing release type argument"
  echo ""
  echo_help
  exit 1
fi

# Show help message if -h, --help, or help passed
case $1 in
  -h | --help | help)
    echo_help
    exit 0
    ;;
esac

# Validate passed release type
case $RELEASE_TYPE in
  patch | minor | major | prepatch | preminor | premajor | prerelease)
    ;;

  *)
    echo "Error! Invalid release type supplied"
    echo ""
    echo_help
    exit 1
    ;;
esac

# validate preid if passed
ALLOWED_PRERELEASE_TYPES=(prepatch preminor premajor prerelease)
if [ -n "$PREID" ]; then
  if [ "$PREID" != "alpha" ] && [ "$PREID" != "beta" ]; then
    echo "Invalid pre_id. It should be either 'alpha' or 'beta'"
    echo ""
    echo_help
    exit 1
  fi

  if [ -n "$RELEASE_TYPE" ]; then
    valid=false

    for type in "${ALLOWED_PRERELEASE_TYPES[@]}"; do
      if [ "$type" = "$RELEASE_TYPE" ]; then
        valid=true
        break
      fi
    done

    if [ "$valid" = false ]; then
      ALLOWED_PRERELEASE_TYPES_STRING=$(printf "'%s', " "${ALLOWED_PRERELEASE_TYPES[@]}")
      echo "Invalid release_type. It should be one of: $ALLOWED_PRERELEASE_TYPES_STRING when pre_id is set"
      echo ""
      echo_help
      exit 1
    fi
  fi
fi

check_github_token

# Make sure our working dir is the repo root directory
cd "$(git rev-parse --show-toplevel)"

echo "Fetching git remotes"
git fetch

GIT_STATUS=$(git status)

if ! grep -q 'On branch master' <<< "$GIT_STATUS"; then
  echo "Error! Must be on master branch to publish"
  exit 1
fi

if ! grep -q "Your branch is up to date with 'origin/master'." <<< "$GIT_STATUS"; then
  echo "Error! Must be up to date with origin/master to publish"
  exit 1
fi

if ! grep -q 'working tree clean' <<< "$GIT_STATUS"; then
  echo "Error! Cannot publish with dirty working tree"
  exit 1
fi

echo "Installing dependencies according to lockfile"
yarn -s install --frozen-lockfile

echo "Running tests"
yarn -s run test

if [ -n "$PREID" ]; then
  echo "Bumping package.json $RELEASE_TYPE, $PREID version and tagging commit"
  yarn -s version --$RELEASE_TYPE --preid $PREID
else
  echo "Bumping package.json $RELEASE_TYPE version and tagging commit"
  yarn -s version --$RELEASE_TYPE
fi

echo "Building"
yarn -s run build

verify_commit_is_signed

echo "Pushing git commit and tag"
git push --follow-tags

# Create release after commit and tag are pushed to ensure package.json
# is bumped in the GitHub release.
create_github_release

echo "Publishing release"
yarn --ignore-scripts publish --non-interactive --access=public

echo "Publish successful!"
echo ""
